
public class Mob extends Player implements Updateable
{   
    public enum Movement
    {
        AllLefts,
        AllRights,
        Random,
        None, 
        BackAndForth, //aggro use with this is most likely
    }
    
    
    final static int ATTACK_COOLDOWN_MELEE = 2;
    final static int ATTACK_COOLDOWN_SPELL = 4;
    final static int ATTACK_DAMAGE_1 = 10;
    final static int ATTACK_DAMAGE_2 = 30;
    
    int aggroRadius;
    Element elemType;
    Movement movementType;
    String displayName;
    Loot loot;
    Direction heading;
    int attackWait = 0;
    int attackDamage;
    boolean attackWithSpells = false;
    
    public Mob(
            int x,
            int y,
            Element elemType, 
            Movement movementType, 
            int aggroRadius,
            int maxHP,
            int maxMP,
            int attackDamage,
            Loot loot,
            String displayName,
            String filePath)
    {
        super(x,y);
        this.aggroRadius = aggroRadius;
        this.elemType = elemType;
        this.movementType = movementType;
        this.maxHP = maxHP;
        this.maxMP = maxMP;
        this.defenseRating = 0; // whatever, all mobs have 0 defense rating
        this.loot = loot;
        this.displayName = displayName;

        this.filePath = filePath;
        this.heading = Direction.Up;
    }
    
    public Mob(
            Direction heading,
            int x,
            int y,
            Element elemType, 
            Movement movementType, 
            int aggroRadius,
            int maxHP,
            int maxMP,
            int attackDamage,
            Loot loot,
            String displayName,
            String filePath)
    {
        super(x,y);
        this.heading = heading;
        this.aggroRadius = aggroRadius;
        this.elemType = elemType;
        this.movementType = movementType;
        this.maxHP = maxHP;
        this.maxMP = maxMP;
        this.defenseRating = 0; // whatever, all mobs have 0 defense rating
        this.loot = loot;
        this.attackDamage = attackDamage;
        this.displayName = displayName;
        this.filePath = filePath;
        this.heading = Direction.Up;
    }
    
    public Mob(int x, int y)
    {
        super(x,y);
        this.aggroRadius = 0;
        this.elemType = Element.Unknown;
        this.movementType = Movement.None;
        this.maxHP = 5;
        this.maxMP = 5;
        this.defenseRating = 0;
        this.loot = null;
        this.displayName = "Unknown";   
        this.filePath = "./images/Unknown.bmp";
        this.heading = Direction.Up;
    }
    
    void takeDamage(double baseDamage)
    {
        double defense = this.defenseRating;
        if(this.defenseRating <=0.5)
        {
            defense = 0.5;
        }
        this.currentHP-=baseDamage/defense;
    }
    
    public void move()
    {   
        int initX = this.x;
        int initY = this.y;
        if(this.movementType == Movement.AllRights)
        {
            if(tryMove(RelativeMove.Right)){}
            else if(tryMove(RelativeMove.Forward)){}
            else if(tryMove(RelativeMove.Left)){}
            else if(tryMove(RelativeMove.Back)){}
        }
        else if(this.movementType == Movement.AllLefts)
        {
            if(tryMove(RelativeMove.Left)){}
            else if(tryMove(RelativeMove.Forward)){}
            else if(tryMove(RelativeMove.Right)){}
            else if(tryMove(RelativeMove.Back)){}
        }
        else if(this.movementType == Movement.BackAndForth)
        {
            if(tryMove(RelativeMove.Forward)){}
            else if(tryMove(RelativeMove.Back)){}
        }
        if(this.x != initX || this.y!=initY)
        {
                if(this.x <13 && this.y<13)
                {
                    //map[this.x][this.y].gameObject = this;
                    map[this.x][this.y].gameObject = this;
                    map[this.x][this.y].update();
                }
                if(initX <13 && initY<13)
                {
                    map[initX][initY].gameObject = null;
                    map[initX][initY].update();
                }
        }
}
    
    private boolean tryMove(RelativeMove rm) 
    {
        int nextX = this.x;
        int nextY = this.y;
        if(this.heading == Direction.Up)
        {
            if (rm == RelativeMove.Right)
            {
                nextX++;
            }
            else if (rm == RelativeMove.Left)
            {
                nextX--;
            }
            else if(rm == RelativeMove.Forward)
            {
                nextY--;
            }
            else if (rm == RelativeMove.Back)
            {
                nextY++;
            }
        }
        else if(this.heading == Direction.Down)
        {
            if (rm == RelativeMove.Right)
            {
                nextX--;
            }
            else if (rm == RelativeMove.Left)
            {
                nextX++;
            }
            else if(rm == RelativeMove.Forward)
            {
                nextY++;
            }
            else if (rm == RelativeMove.Back)
            {
                nextY--;
            }
        }
        else if(this.heading == Direction.Right)
        {
            if (rm == RelativeMove.Right)
            {
                nextY++;
            }
            else if (rm == RelativeMove.Left)
            {
                nextY--;
            }
            else if(rm == RelativeMove.Forward)
            {
                nextX++;
            }
            else if (rm == RelativeMove.Back)
            {
                nextX--;
            }
        }
        else if(this.heading == Direction.Left)
        {
            if (rm == RelativeMove.Right)
            {
                nextY--;
            }
            else if (rm == RelativeMove.Left)
            {
                nextY++;
            }
            else if(rm == RelativeMove.Forward)
            {
                nextX--;
            }
            else if (rm == RelativeMove.Back)
            {
                nextX++;
            }
        }
        
        for(GameObject go: GameObject.gameObjects)
        {
            if(nextX == go.x && nextY == go.y)
            {
                if ((go instanceof Spell) && (((Spell)go).playerSpell))
                    this.takeDamage(((Spell)go).damage);
                else
                    return false;
            }
        }
        
        if(this.x>nextX)
        {
            this.heading = Direction.Left;
        }
        else if(this.x<nextX)
        {
            this.heading = Direction.Right;
        }
        else if(this.y>nextY)
        {
            this.heading = Direction.Up;
        }
        else if(this.y<nextY)
        {
            this.heading = Direction.Down;
        }
        this.x = nextX;
        this.y = nextY;
        return true;
        
    }
    
    public void update()
    {
        move();     
        tryAttack();
    }
    
    public void tryAttack()
    {
        if(this.attackWait>0)
        {
            this.attackWait--;
            return;
        }
        
        if(attackWithSpells && activeSpell != null)
        {
            GameObject.gameObjects.add(
                    SpellCreator.copy(
                            1.0, this.activeSpell, 
                            false, this.x, this.y, this.heading
                    ));
            this.attackWait = ATTACK_COOLDOWN_SPELL;
            return;
        }
        
        for(GameObject go: GameObject.gameObjects)
        {
            if((go instanceof Player) && !(go instanceof Mob))
            {
            int dx = this.x - go.x;
            int dy = this.y - go.y;
            if(dx>=-1&&dx<=1)
            {
                if(dy>=-1&&dy<=1)
                {
                    //player take damage
                    Player p = (Player)go;
                    p.takeDamage(this.attackDamage);
                    this.attackWait = ATTACK_COOLDOWN_MELEE;
                }
            }
            }
        }
    }
    
    private enum RelativeMove
    {
    Forward,
    Back,
    Left,
    Right
    }
        
}
